#include "stdafx.h"
#include "CppUnitTest.h"

#include <HSModel/Model3D.h>
#include <HSModel/BoundingBox.h>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace HSModelTests
  {		
  TEST_CLASS(Model3DTest)
    {
    public:		
      TEST_METHOD(ShouldIteratePoints)
        {
        Model3D model;
        Point3DID point1 = model.AddPoint(1.0, 2.0, 3.0);
        Point3DID point2 = model.AddPoint(1.0, 5.0, 6.0);
        Point3DID point3 = model.AddPoint(1.0, 8.0, 9.0);

        auto it = model.Points().begin();
        int counter = 0;
        for(; it != model.Points().end(); it++)
          {
          Assert::AreEqual(it->X(), 1.0);
          counter++;
          }

        Assert::AreEqual(counter, 3);
        }

      TEST_METHOD(ShouldIterateTriangles)
        {
        Model3D model;
        Point3DID point1 = model.AddPoint(1.0, 2.0, 3.0);
        Point3DID point2 = model.AddPoint(2.0, 4.0, 6.0);
        Point3DID point3 = model.AddPoint(3.0, 8.0, 9.0);

        model.AddTriangle(point1, point2, point3);
        model.AddTriangle(point1, point2, point3);

        auto it = model.Triangles().begin();
        int counter = 0;
        for(; it != model.Triangles().end(); it++)
          {
          Assert::AreEqual(it->GetPoint(0).X(), 1.0);
          counter++;
          }

        Assert::AreEqual(counter, 2);
        }

      TEST_METHOD(ShouldIterateTrianglesMutable)
        {
        Model3D model;
        Point3DID point1 = model.AddPoint(1.0, 2.0, 3.0);
        Point3DID point2 = model.AddPoint(2.0, 4.0, 6.0);
        Point3DID point3 = model.AddPoint(3.0, 8.0, 9.0);

        model.AddTriangle(point1, point2, point3);
        model.AddTriangle(point1, point2, point3);

        Model3D::Triangle3DIterator it = model.TrianglesMutable().begin();
        int counter = 0;
        for(; it != model.TrianglesMutable().end(); it++)
          {
          Assert::AreEqual(it->GetPoint(0).X(), 1.0);
          it->SetPointsUV(TVector2(1,1), TVector2(2,2), TVector2(3,3));
          Assert::AreEqual(1.0, it->GetPointUV(0).X());
          counter++;
          }

        Assert::AreEqual(counter, 2);
        }
    
      TEST_METHOD(ShouldScaleCorrectly)
        {
        Model3D model;
        Point3DID point1 = model.AddPoint(7.0, 2.0, 3.0);
        Point3DID point2 = model.AddPoint(1.0, 5.0, -6.0);
        Point3DID point3 = model.AddPoint(4.0, -8.0, 9.0);
        Point3DID point4 = model.AddPoint(11.0, 8.0, 9.0);
        BoundingBox box = CalculateBoundingBox(model);

        double sz_x = box.m_max_x - box.m_min_x;
        double sz_y = box.m_max_y - box.m_min_y;
        double sz_z = box.m_max_z - box.m_min_z;

        model.ScaleTransform(TVector3(2.0, 0.75, 1.0));

        BoundingBox new_box = CalculateBoundingBox(model);
        double new_sz_x = new_box.m_max_x - new_box.m_min_x;
        double new_sz_y = new_box.m_max_y - new_box.m_min_y;
        double new_sz_z = new_box.m_max_z - new_box.m_min_z;

        double act_scale_x = new_sz_x / sz_x;
        double act_scale_y = new_sz_y / sz_y;
        double act_scale_z = new_sz_z / sz_z;

        Assert::AreEqual(2.0, act_scale_x);
        Assert::AreEqual(0.75, act_scale_y);
        Assert::AreEqual(1.0, act_scale_z);
        }

      TEST_METHOD(ShouldScaleUniformCorrectly)
        {
        Model3D model;
        Point3DID point1 = model.AddPoint(7.0, 2.0, 3.0);
        Point3DID point2 = model.AddPoint(1.0, 5.0, -6.0);
        Point3DID point3 = model.AddPoint(4.0, -8.0, 9.0);
        Point3DID point4 = model.AddPoint(11.0, 8.0, 9.0);
        BoundingBox box = CalculateBoundingBox(model);

        double sz_x = box.m_max_x - box.m_min_x;
        double sz_y = box.m_max_y - box.m_min_y;
        double sz_z = box.m_max_z - box.m_min_z;

        model.ScaleTransform(2.275);

        BoundingBox new_box = CalculateBoundingBox(model);
        double new_sz_x = new_box.m_max_x - new_box.m_min_x;
        double new_sz_y = new_box.m_max_y - new_box.m_min_y;
        double new_sz_z = new_box.m_max_z - new_box.m_min_z;

        double act_scale_x = new_sz_x / sz_x;
        double act_scale_y = new_sz_y / sz_y;
        double act_scale_z = new_sz_z / sz_z;

        Assert::AreEqual(2.275, act_scale_x);
        Assert::AreEqual(2.275, act_scale_y);
        Assert::AreEqual(2.275, act_scale_z);
        }

      TEST_METHOD(ShouldContainTriangle)
        {
        Model3D model;
        Point3DID point1 = model.AddPoint(1.0, 2.0, 3.0);
        Point3DID point2 = model.AddPoint(2.0, 4.0, 6.0);
        Point3DID point3 = model.AddPoint(3.0, 8.0, 9.0);
        Point3DID point4 = model.AddPoint(5.0, 10.0, 9.0);
        model.AddTriangle(point1, point2, point3);
        model.AddTriangle(point1, point2, point4);
        
        TTriangle3 triangle_in_1;
        triangle_in_1.V[2] = TVector3(1.0, 2.0, 3.0);
        triangle_in_1.V[0] = TVector3(2.0, 4.0, 6.0);
        triangle_in_1.V[1] = TVector3(3.0, 8.0, 9.0);

        TTriangle3 triangle_in_2;
        triangle_in_2.V[2] = TVector3(1.0, 2.0, 3.0);
        triangle_in_2.V[0] = TVector3(2.0, 4.0, 6.0);
        triangle_in_2.V[1] = TVector3(3.0, 8.0, 9.0);

        TTriangle3 triangle_out;
        triangle_out.V[1] = TVector3(1.0, 2.0, 3.0);
        triangle_out.V[0] = TVector3(5.0, 10.0, 9.0);
        triangle_out.V[2] = TVector3(3.0, 8.0, 9.0);

        Assert::IsTrue(model.ContainsTriangle(triangle_in_1));
        Assert::IsTrue(model.ContainsTriangle(triangle_in_2));
        Assert::IsFalse(model.ContainsTriangle(triangle_out));        
        
        }

    };
  }